#include "../quickjs.c"

/* 源码解析管理器 */
struct JSParseState {
  JSContext *ctx;
  int last_line_num;  /* line number of last token */
  int line_num;       /* line number of current offset */
  const char *filename;
  JSToken token; /* 当前识别到的token */
  BOOL got_lf; /* true if got line feed before the current token */
  const uint8_t *last_ptr;
  const uint8_t *buf_ptr;
  const uint8_t *buf_end;

  /* current function code */
  JSFunctionDef *cur_func; /* 解析的过程中，需要将生成字节码存储到对应的函数定义结构的byte_code上 */
  BOOL is_module; /* parsing a module */
  BOOL allow_html_comments;
};
/* 函数定义 */
struct JSFunctionDef {
    JSContext *ctx;
    struct JSFunctionDef *parent;
    int parent_cpool_idx; /* index in the constant pool of the parent
                             or -1 if none */
    int parent_scope_level; /* scope level in parent at point of definition */
    struct list_head child_list; /* list of JSFunctionDef.link */
    struct list_head link;

    BOOL is_eval; /* TRUE if eval code，global/module代码对应的函数定义 */
    int eval_type; /* only valid if is_eval = TRUE */
    BOOL is_global_var; /* TRUE if variables are not defined locally:
                           对于global/module/非严格模式下的代码为true
                           global/module或者非严格模式下的函数体内部var变量需要提升
                           或者global/module下的scope level 1中的let/const/func_decl变量需要提升 */
    BOOL is_func_expr; /* TRUE if function expression */
    BOOL has_home_object; /* TRUE if the home object is available */
    BOOL has_prototype; /* true if a prototype field is necessary */
    BOOL has_simple_parameter_list;
    BOOL has_use_strict; /* to reject directive in special cases */
    BOOL has_eval_call; /* true if the function contains a call to eval() */
    BOOL has_arguments_binding; /* true if the 'arguments' binding is
                                   available in the function */
    BOOL has_this_binding; /* true if the 'this' and new.target binding are
                              available in the function */ /* 函数中是否可以绑定this和new.target */
    BOOL new_target_allowed; /* true if the 'new.target' does not
                                throw a syntax error */
    BOOL super_call_allowed; /* true if super() is allowed */
    BOOL super_allowed; /* true if super. or super[] is allowed */
    BOOL arguments_allowed; /* true if the 'arguments' identifier is allowed */
    BOOL is_derived_class_constructor;
    BOOL in_function_body;
    BOOL backtrace_barrier;
    JSFunctionKindEnum func_kind : 8;
    JSParseFunctionEnum func_type : 8;
    uint8_t js_mode; /* bitmap of JS_MODE_x */
    JSAtom func_name; /* JS_ATOM_NULL if no name */

    /* 函数中定义的变量列表 */
    JSVarDef *vars;
    int var_size; /* allocated size for vars[] */
    int var_count;
    
    /* 函数参数列表 */
    JSVarDef *args;
    int arg_size; /* allocated size for args[] */
    int arg_count; /* number of arguments */
    int defined_arg_count;
    
    int var_object_idx; /* -1 if none */
    int arguments_var_idx; /* -1 if none */
    int func_var_idx; /* variable containing the current function (-1
                         if none, only used if is_func_expr is true) */
    int eval_ret_idx; /* variable containing the return value of the eval, -1 if none */
    int this_var_idx; /* variable containg the 'this' value, -1 if none */
    int new_target_var_idx; /* variable containg the 'new.target' value, -1 if none */
    int this_active_func_var_idx; /* variable containg the 'this.active_func' value, -1 if none */
    int home_object_var_idx;
    BOOL need_home_object;

    /* 作用域信息 */
    int scope_level;    /* index into fd->scopes if the current lexical scope */
    int scope_first;    /* index into vd->vars of first lexically scoped variable */
    int scope_size;     /* allocated size of fd->scopes array */
    int scope_count;    /* number of entries used in the fd->scopes array */
    JSVarScope *scopes;
    JSVarScope def_scope_array[4];

    /* global/module代码中定义的var变量或者scope level 1中声明的let/const/func_decl变量 */
    int hoisted_def_count;
    int hoisted_def_size;
    JSHoistedDef *hoisted_def;

    DynBuf byte_code;
    int last_opcode_pos; /* -1 if no last opcode */
    int last_opcode_line_num;
    BOOL use_short_opcodes; /* true if short opcodes are used in byte_code */

    /* 当解析到该label时（这时就可以确定label的最终地址了），
       根据label_slots中的记录更新跳转语句的地址
       以及label在bytecode中的地址 */
    LabelSlot *label_slots;
    int label_size; /* allocated size for label_slots[] */
    int label_count;
    BlockEnv *top_break; /* break/continue label stack */

    /* constant pool (strings, functions, numbers) */
    JSValue *cpool; /* 存放作用域中定义的函数 */
    uint32_t cpool_count;
    uint32_t cpool_size;

    /* list of variables in the closure */
    int closure_var_count;
    int closure_var_size;
    JSClosureVar *closure_var;

    JumpSlot *jump_slots;
    int jump_size;
    int jump_count;

    LineNumberSlot *line_number_slots;
    int line_number_size;
    int line_number_count;
    int line_number_last;
    int line_number_last_pc;

    /* pc2line table */
    JSAtom filename;
    int line_num;
    DynBuf pc2line;

    char *source;  /* raw source, utf-8 encoded */
    int source_len;

    JSModuleDef *module; /* != NULL when parsing a module */
};

struct JSVarDef {
  JSAtom var_name;
  int scope_level; /* 变量所处的作用域层级，在fd->scope中的index，为0表示var声明的变量和参数所处的作用域 */
  int scope_next; /* 当前作用域的上一个变量或者父作用域的最后一个变量，在fd->vars中的index */
  uint8_t is_func_var : 1; /* used for the function self reference */
  uint8_t is_const : 1;
  uint8_t is_lexical : 1;
  uint8_t is_captured : 1; /* 变量是否在子作用域中使用到 */
  uint8_t var_kind : 4; /* see JSVarKindEnum */
  /* only used during compilation: function pool index for lexical
     variables with var_kind =
     JS_VAR_FUNCTION_DECL/JS_VAR_NEW_FUNCTION_DECL or scope level of
     the definition of the 'var' variables (they have scope_level =
     0) */
  /* var语法声明的变量作用域需要提升，下面这个字段用于记录var变量声明时所处的作用域，有可能是函数作用域下面的块级作用域 */
  int func_pool_or_scope_idx : 24; /* only used during compilation */
}
struct JSClosureVar {
  uint8_t is_local : 1;
  uint8_t is_arg : 1;
  uint8_t is_const : 1;
  uint8_t is_lexical : 1;
  uint8_t var_kind : 3; /* see JSVarKindEnum */
  /* 9 bits available */
  uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the
                    parent function. otherwise: index to a closure
                    variable of the parent function */
  JSAtom var_name;
};

struct JSVarRef {
  union {
    JSGCObjectHeader header; /* must come first */
    struct {
      int __gc_ref_count; /* corresponds to header.ref_count */
      uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */

      /* 0 : the JSVarRef is on the stack. header.link is an element
         of JSStackFrame.var_ref_list.
         1 : the JSVarRef is detached. header.link has the normal meanning 
      */
      uint8_t is_detached : 1;
      uint8_t is_arg : 1;
      uint16_t var_idx; /* index of the corresponding function variable on
                                 the stack */
    };
  };
  JSValue *pvalue; /* pointer to the value, either on the stack or
                        to 'value' */
  JSValue value; /* used when the variable is no longer on the stack */
}

struct JSValue {
  JSValueUnion u;
  int64_t tag;
};
union JSValueUnion {
  int32_t int32; // 整数、布尔值、null、undefined、uninitiated
  double float64; // 浮点数
  void *ptr; // 其他类型
};
enum {
  /* all tags with a reference count are negative */
  JS_TAG_FIRST       = -11, /* first negative tag */
  JS_TAG_BIG_DECIMAL = -11,
  JS_TAG_BIG_INT     = -10,
  JS_TAG_BIG_FLOAT   = -9,
  JS_TAG_SYMBOL      = -8,
  JS_TAG_STRING      = -7,
  JS_TAG_MODULE      = -3, /* used internally */
  JS_TAG_FUNCTION_BYTECODE = -2, /* used internally */
  JS_TAG_OBJECT      = -1,

  JS_TAG_INT         = 0,
  JS_TAG_BOOL        = 1,
  JS_TAG_NULL        = 2,
  JS_TAG_UNDEFINED   = 3,
  JS_TAG_UNINITIALIZED = 4,
  JS_TAG_CATCH_OFFSET = 5,
  JS_TAG_EXCEPTION   = 6,
  JS_TAG_FLOAT64     = 7,
  /* any larger tag is FLOAT64 if JS_NAN_BOXING */
};

/* 代表一个执行堆栈，也就是函数执行单元 */
struct JSStackFrame {
  struct JSStackFrame *prev_frame; /* NULL if first stack frame */
  JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */
  JSValue *arg_buf; /* 参数列表 arguments */
  JSValue *var_buf; /* 局部变量列表 variables */
  struct list_head var_ref_list; /* list of JSVarRef.link */
  const uint8_t *cur_pc; /* only used in bytecode functions : PC of the
                        instruction after the call */
  int arg_count; /* 参数个数 */
  int js_mode; /* 0 or JS_MODE_MATH for C functions */
  /* only used in generators. Current stack pointer value. NULL if
     the function is running. */
  JSValue *cur_sp;
};

/*
// a += 1;
js_parse_assign_expr

// a ? b : c
js_parse_cond_expr
 
// a ?? b
js_parse_coalesce_expr 

// a || b, a && b
js_parse_logical_and_or 
 
// 二元表达式（优先级）
js_parse_expr_binary 
 
// 一元表达式 +1 ++a
js_parse_unary 
 
// number, string, regexp, function, class, ident
js_parse_postfix_expr 
*/

struct JSRuntime {
    JSMallocFunctions mf; /* 内存分配函数 */
    JSMallocState malloc_state; /* 内存分配状态 */
    const char *rt_info;

    int atom_hash_size; /* power of two, 支持不同hash的最大个数 */
    int atom_count; /* atom的个数 */
    int atom_size; /* 支持存放atom的最大个数 */
    int atom_count_resize; /* resize hash table at this count */
    uint32_t *atom_hash; /* 以atom的hash为index，存储atom在atom_array中的位置。 */
    JSAtomStruct **atom_array; /* atom_array[atom_hash[hash(atom)]] == atom */
    int atom_free_index; /* 0 = none，atom_array中空闲的第一个位置 */

    int class_count;    /* size of class_array */
    JSClass *class_array;

    struct list_head context_list; /* list of JSContext.link */
    /* list of JSGCObjectHeader.link. List of allocated GC objects (used
       by the garbage collector) */
    struct list_head gc_obj_list;
    /* list of JSGCObjectHeader.link. Used during JS_FreeValueRT() */
    struct list_head gc_zero_ref_count_list;
    struct list_head tmp_obj_list; /* used during GC */
    JSGCPhaseEnum gc_phase : 8;
    size_t malloc_gc_threshold;
#ifdef DUMP_LEAKS
    struct list_head string_list; /* list of JSString.link */
#endif

    JSInterruptHandler *interrupt_handler;
    void *interrupt_opaque;

    JSHostPromiseRejectionTracker *host_promise_rejection_tracker;
    void *host_promise_rejection_tracker_opaque;

    struct list_head job_list; /* list of JSJobEntry.link */

    JSModuleNormalizeFunc *module_normalize_func;
    JSModuleLoaderFunc *module_loader_func;
    void *module_loader_opaque;

    BOOL can_block : 8; /* TRUE if Atomics.wait can block */

    /* Shape hash table */
    int shape_hash_bits;
    int shape_hash_size;
    int shape_hash_count; /* number of hashed shapes */
    JSShape **shape_hash;
#ifdef CONFIG_BIGNUM
    bf_context_t bf_ctx;
    JSNumericOperations bigint_ops;
    JSNumericOperations bigfloat_ops;
    JSNumericOperations bigdecimal_ops;
    uint32_t operator_count;
#endif
    void *user_opaque;
};
